<!-- @/components/ReviewComponent.vue -->
<!-- 审核父组件 -->
<template>
  <div class="review-container">
    <!-- el-card -> 卡片组件，提供了整洁 & 富有层次感的容器 -->
    <el-card class="review-card">
      <!-- 卡片头部 -> 内容审核四个字 -->
      <template #header>
        <div class="card-header">
          <span>内容审核</span>
        </div>
      </template>

      <!-- 卡片的主体是表格，用el-table组件 -->
      <!-- :data -> 是相应数据，使用的是reviewList数据, 下面表格项中的prop就是reviewList中的字段 -->
      <!-- style="width: 100%" -> 表格宽度为100%，border -> 表格边框 -->
      <el-table :data="reviewList" style="width: 100%" border>
        <!-- 第一列表格项 -->
        <!-- prop -> 表示数据项的字段 -->
        <!-- label -> 表示数据项的标题 -->
        <!-- width -> 表示数据项的宽度 -->
        <el-table-column prop="id" label="ID" width="80"/>
        <!-- 第二列表格项 -->
        <el-table-column prop="title" label="标题"/>
        <!-- 第三列表格项 -->
        <el-table-column prop="author" label="作者" width="120"/>
        <!-- 第四列表格项 -->
        <el-table-column prop="submitTime" label="提交时间" width="180"/>
        <!-- 第五列表格项 -->
        <el-table-column label="状态" width="120">
          <!-- 列表项模板，使用#default="{row}"，拿到当前行的数据，方便下面进行函数调用的时候参数使用 -->
          <template #default="{row}">
            <!-- el-tag -> 标签组件，用于显示标记信息 -->
            <!-- :type ->
              表示标签的类型，通过getStatusTagType方法获取
              这个方法是map映射，将 ReviewStatus 转换为对应的标签类型
              传递的参数是row.status，表示当前行的状态
              返回的结果是warning: 警告, success: 成功, danger: 危险
            -->
            <!--
              内容是状态文本，对于状态文本的获取是通过getStatusText方法获取
              这个方法是map映射，将 ReviewStatus 转换为对应的状态文本
              传递的参数是row.status，表示当前行的状态
              返回的结果是待审核, 已通过, 已拒绝
            -->
            <el-tag :type="getStatusTagType(row.status)">
              {{ getStatusText(row.status) }}
            </el-tag>
          </template>
        </el-table-column>
        <!-- 第六列表格项, 操作栏，这里放的是两个按钮，是通过还是拒绝？表示审核的操作 -->
        <el-table-column label="操作" width="300">
          <!-- 列表项模板，使用#default="{row}"，拿到当前行的数据，方便下面进行函数调用的时候参数使用 -->
          <template #default="{ row }">
            <!-- el-button -> 按钮组件，用于显示按钮 -->
            <!-- size -> 表示按钮的大小，这里设置为small，表示小按钮 -->
            <!-- type -> 表示按钮的类型，这里设置为primary，表示主要按钮 -->
            <!--
              通过点击按钮，调用handleReview方法
              传递两个参数，第一个是row.id，第二个是'approve'，表示通过
            -->
            <!--
              :disabled -> 表示按钮是否禁用，这里通过判断当前行的状态是否为待审核
              如果是，则禁用按钮，即之后待审核的状态才会可以点击按钮进行操作
            -->
            <el-button
              size="small"
              type="primary"
              @click="handleReview(row.id, 'approve')"
              :disabled="row.status !== 'pending'"
            >
              通过
            </el-button>

            <!-- el-button -> 按钮组件，用于显示按钮 -->
            <!-- size -> 表示按钮的大小，这里设置为small，表示小按钮 -->
            <!-- type -> 表示按钮的类型，这里设置为primary，表示主要按钮 -->
            <!--
              通过点击按钮，调用handleReview方法
              传递两个参数，第一个是row.id，第二个是'reject'，表示拒绝
            -->
            <!--
              :disabled -> 表示按钮是否禁用，这里通过判断当前行的状态是否为待审核
              如果是，则禁用按钮，即之后待审核的状态才会可以点击按钮进行操作
            -->
            <el-button
              size="small"
              type="danger"
              @click="handleReview(row.id, 'reject')"
              :disabled="row.status !== 'pending'"
            >
              拒绝
            </el-button>

            <!-- el-button -> 按钮组件，用于显示按钮 -->
            <!-- size -> 表示按钮的大小，这里设置为small，表示小按钮 -->
            <!-- type -> 表示按钮的类型，这里设置为primary，表示主要按钮 -->
            <!--
              通过点击按钮，调用showReviewDetail方法
              传递一个参数，row.id，表示当前行的id
              其实就是将reviewDialogVisible的内容置为true，这样就能显示详情对话框了，这个对话框再调用子组件
            -->
            <el-button
              size="small"
              type="primary"
              @click="showReviewDetail(row.id)"
            >
              详情
            </el-button>
          </template>
        </el-table-column>
      </el-table>

      <!-- 分页组件 -> 用于分页 -->
      <!-- :current-page ->
        表示当前页码，这里绑定了pagination.currentPage
        pagination.currentPage是响应式数据，所以这里会自动更新
      -->
      <!-- :page-size ->
        表示每页显示的条数，这里绑定了pagination.pageSize
        pagination.pageSize是响应式数据，所以这里会自动更新
      -->
      <!-- :total ->
        表示总条数, 这里绑定了pagination.total
        pagination.total是响应式数据，所以这里会自动更新
      -->
      <!-- :page-sizes ->
        表示每页显示的条数，这里绑定了[5, 10, 20, 50]
        这个数组是静态数据，所以这里不会自动更新
      -->
      <!-- layout -> 表示分页布局，这里绑定了'total, sizes, prev, pager, next, jumper'-->
      <!-- @current-change ->
        表示当前页码改变时，调用fetchReviewList方法
        这个方法用于获取当前页码的数据
      -->
      <!-- @size-change ->
        表示每页显示的条数改变时，调用handleSizeChange方法
        这个方法用于 重置当前页码大小之后，获取当前页码的数据fetchReviewList
      -->
      <el-pagination
        class="pagination"
        v-model:current-page="pagination.currentPage"
        v-model:page-size="pagination.pageSize"
        :total="pagination.total"
        :page-sizes="[5, 10, 20, 50]"
        layout="total, sizes, prev, pager, next, jumper"
        @current-change="fetchReviewList"
        @size-change="handleSizeChange"
      />
    </el-card>

    <!-- 审核详情对话框, 在这个对话框中，将会调用子组件ReviewDetail -->
    <el-dialog v-model="reviewDialogVisible" title="审核详情" width="50%">
      <!-- :content="selectedContent", 父组件向子组件传递参数，传递的内容是selectedContent，父组件通过content接收 -->
      <!-- @submit ->
        自定义事件submit, 这个在子组件中将会定义和发送
        然后将参数传递过来之后，将调用handleReviewSubmit
      -->
      <!-- @cancel ->
        自定义事件cancel, 这个在子组件中将会定义和发送
        然后将参数传递过来之后，将调用reviewDialogVisible = false
      -->
      <ReviewDetail
        :content="selectedContent"
        @submit="handleReviewSubmit"
        @cancel="reviewDialogVisible = false"
      />
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
// 引入vue的常用方法，ref -> 用于创建响应式数据, onMounted -> 用于在组件挂载完成后执行代码
import {onMounted, ref} from 'vue'
// 引入element-plus的常用方法，ElMessage -> 用于显示消息提示，ElMessageBox -> 用于显示对话框
import {ElMessage, ElMessageBox} from 'element-plus'
// 引入自定义的api，这里引入的是review.ts中的ReviewItem -> 审核项数据结构和审核状态
import type {ReviewItem, ReviewStatus} from '@/api/types/review'
// 引入子组件ReviewDetail, 在上面引入
import ReviewDetail from './ReviewDetail.vue'

// 审核列表数据 -> 初始化为空数组，在挂载(onMounted)之后，会调用fetchReviewList方法赋值
const reviewList = ref<ReviewItem[]>([])
// 选中的内容 -> 初始化为空字符串
// 在调用showReviewDetail方法时，会将当前行的内容赋值给selectedContent
const selectedContent = ref<string>('')
// 审核详情对话框是否可见 -> 初始化为false
// 在调用showReviewDetail方法时，会将reviewDialogVisible设置为true
const reviewDialogVisible = ref<boolean>(false)

// 分页配置 -> 初始化为一个对象，对象中有三个属性，currentPage, pageSize, total
const pagination = ref({
  currentPage: 1,
  pageSize: 10,
  total: 0
})

// 获取审核状态文本
// 就是一个map, key为ReviewStatus, value为对应的文本
// 如果ReviewStatus的值不在map中，则返回未知状态，在上面显示状态的时候使用
const getStatusText = (status: ReviewStatus): string => {
  const statusMap: Record<ReviewStatus, string> = {
    pending: '待审核',
    approved: '已通过',
    rejected: '已拒绝'
  }
  return statusMap[status] || '未知状态'
}

// 显示审核详情 -> 点击按钮时调用
// 修改reviewDialogVisible为true，就能显示对话框了
// selectedContent -> 父组件向子组件传递参数，传递的内容是当前行的内容
const showReviewDetail = (id: number) => {
  // 获取当前行的数据
  const review = reviewList.value.find(item => item.id === id)
  // 判断当前行数据是否存在
  // 如果存在，则将当前行的数据赋值给selectedContent 并将reviewDialogVisible设置为true
  // 然后就能显示对话框了
  if (review) {
    selectedContent.value = review.content
    reviewDialogVisible.value = true
  }
}

// 获取状态标签类型
// 其实就是一个map, key为ReviewStatus, value为对应的标签类型
// 如果ReviewStatus的值不在map中，则返回空字符串，在显示标签的时候使用，定义标签的type
// 会显示不同的颜色，颜色不同，表示不同的状态
const getStatusTagType = (status: ReviewStatus): string => {
  const typeMap: Record<ReviewStatus, string> = {
    pending: 'warning',
    approved: 'success',
    rejected: 'danger'
  }
  return typeMap[status] || ''
}

// 获取审核列表
// 正常来说，这里是调用接口获取数据，这里模拟数据
const fetchReviewList = async () => {
  try {
    // 模拟数据
    // 这里模拟数据，生成10条数据
    // 设置数据reviewList等于生成出来的数据
    reviewList.value = Array.from({length: 10}, (_, i) => ({
      id: i + 1,
      title: `测试内容 ${i + 1}`,
      author: `作者 ${i % 3 + 1}`,
      submitTime: new Date().toLocaleString(),
      status: ['pending', 'approved', 'rejected'][i % 3] as ReviewStatus,
      content: `这是第 ${i + 1} 条测试内容的详细内容...`
    }))
    // 设置分页总数total等于30
    pagination.value.total = 30
  } catch (error) {
    // 显示错误信息
    ElMessage.error('获取审核列表失败')
    console.error(error)
  }
}

// 处理审核操作
// 传入的是当前行的id和操作类型 -> approve: 通过, reject: 拒绝
const handleReview = async (id: number, action: 'approve' | 'reject') => {
  try {
    // 下面弹出确认框，根据操作类型判断是否通过审核
    await ElMessageBox.confirm(
      `确定要${action === 'approve' ? '通过' : '拒绝'}该内容吗?`,
      '提示',
      {confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning'}
    )

    // 更新状态
    // 先找到当前行， item.id === id的项就是当前行
    const item = reviewList.value.find(item => item.id === id)
    if (item) {
      // 修改状态
      item.status = action === 'approve' ? 'approved' : 'rejected'
    }

    ElMessage.success('操作成功')
  } catch (error) {
    console.error(error)
  }
}

// 子组件中详情查看完成的按钮，先关闭对话框，然后显示消息，根据当前的操作类型显示不同的消息
const handleReviewSubmit = (action: 'approve' | 'reject') => {
  reviewDialogVisible.value = false
  ElMessage.success(`已${action === 'approve' ? '通过' : '拒绝'}审核`)
}

// 每页条数变化
// 修改分页配置，然后重新获取数据
const handleSizeChange = (size: number) => {
  pagination.value.pageSize = size
  fetchReviewList()
}

// 初始化加载数据，直接调用fetchReviewList方法
onMounted(() => {
  fetchReviewList()
})
</script>

<style scoped>
.review-container {
  padding: 20px; /* 设置内边距是20像素 */
}

.review-card {
  margin-bottom: 20px; /* 设置底边的外边距是20像素 */
}

.pagination {
  margin-top: 20px; /* 添加20像素的顶边外边距 */
  justify-content: flex-end; /* 将分页器放在右侧 */
}
</style>
